/*
MIT License 

Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов, 

https://bmstu.codes/lsx/simodo/loom
*/

#ifndef simodo_interpret_host_fuze_ParsingTableBuilder_LR1
#define simodo_interpret_host_fuze_ParsingTableBuilder_LR1

/*! \file ParsingTableBuilder_LR1.h
    \brief Формирование таблицы разбора методом LR(1)
*/

#include "simodo/interpret/builtins/hosts/fuze/ParsingTableBuilder_abstract.h"

#include <tuple>

namespace simodo::interpret::builtins
{
    struct DepthPair
    {
        int     depth;
        size_t  weight;
    };

    struct DepthPairComparator
    {
        bool operator () (const DepthPair& top, const DepthPair& btn) const
        {
            return (top.depth == btn.depth && top.weight > btn.weight) || top.depth < btn.depth;
        }
    };

    /*!
     * \brief Класс формирование таблицы разбора по заданным правилам грамматики методом LR(1)
     */
    class ParsingTableBuilder_LR1 : public ParsingTableBuilder_abstract
    {
        std::multimap<uint64_t,size_t> _position_index;    ///< Отображение позиции состояния (rno,pos) в номер состояния

    public:
        ParsingTableBuilder_LR1() = delete;    ///< Пустой конструктор не поддерживается!

        /*!
         * \brief Конструктор построителя таблицы разбора методом LR(1)
         * \param m             Интерфейсная ссылка на объект обеспечения вывода информации в вызываемую программу
         * \param grammar_name  Наименование грамматики, которую нужно загрузить
         * \param g             Структура грамматики
         * \param strict_rule_consistency Признак строгости в проверках согласованности таблицы разбора
         */
        ParsingTableBuilder_LR1(const inout::uri_set_t & files,
                                inout::Reporter_abstract & m,
                                const std::string & grammar_name,
                                parser::Grammar & g,
                                bool strict_rule_consistency=true)
            : ParsingTableBuilder_abstract(files, m, grammar_name, g, strict_rule_consistency)
        {}

    protected:
        /*!
         * \brief Метод построения таблицы состояний
         */
        virtual void fillStateTable() override;

        /*!
         * \brief Основной метод построения таблицы разбора по заполненным перечням состояний (строки)
         * и символов грамматики (колонок)
         * \return true, если формирование завершилось успешно, иначе - false
         */
        virtual bool fillParseTable() override;

    protected:
        /*!
         * \brief Метод построения набора состояний для заданного номера состояния (линии) таблицы разбора
         * (используется рекурсивно)
         * \param state_no Номер состояния таблицы разбора
         */
        void fillState(size_t state_no);

        /*!
         * \brief Метод поиска заданной основной позиции в наборе состояний
         * \param rno       Номер правила в перечне правил грамматики
         * \param pos       Позиция состояния внутри правила
         * \param lookahead Предпросмотры
         * \return    Номер состояния, если оно найдено или 0, если не найдено (нулевое состояние является
         * исскуственным и ни когда не может быть найдено)
         */
        size_t findMainPosition(size_t rno, size_t pos, const std::set<inout::Lexeme> & lookahead) const;

        /*!
         * \brief Метод формирования замыканий для основной позиции заданного состояния
         *
         * Метод заполнения всех наведённых позиций (замыканий) при раскрутке символа грамматики,
         * стоящего на позиции (используется рекурсивно)
         *
         * \param state_no          Номер состояния
         * \param rno               Индекс правила грамматики
         * \param pos               Позиция
         * \param depth             Текущая глубина раскрутки
         * \param position_multiset Формируемая в данном методе коллекция позиция (для сортировки по их весам)
         */
        void fillClosure(size_t state_no, size_t rno, size_t pos, int depth,
                         std::multimap<DepthPair,parser::FsmStatePosition,DepthPairComparator> & position_multiset);


        /*!
         * \brief Определяет и заполняет предпросмотры для сформированных неосновных позиций заданного состояния
         * \param state_no                  Номер состояния
         * \param position_initial_count    Индекс начала неосновных позиций
         * \param prod_lookahead_set        Предпросмотры продукций для заданного состояния
         */
        void fillLookahead(size_t state_no, size_t position_initial_count,
                           std::map<std::u16string , std::set<inout::Lexeme>> & prod_lookahead_set);

        /*!
         * \brief Формирует множество терминальных символов для заданной продукции
         * \param prod      Продукция
         * \param terminals Множество терминальных символов
         * \param processed Множество обработанных нетерминалов для предотвращения зацикливания
         */
        void fillStartingTerminalsByProd(const inout::Lexeme & prod, std::set<inout::Lexeme> & terminals, std::set<inout::Lexeme> & processed);

        /*!
         * \brief Заполнение конкретной ячейки в таблице разбора
         * \param line      Номер состояние (строка таблицы)
         * \param column    Номер символа грамматики (колонка таблицы)
         * \param value     Значение
         * \return true, если заполнение завершилось успешно, иначе - false
         */
        bool insertValue(size_t line, size_t column, parser::Fsm_value_t value);

        /*!
         * \brief Добавление списка позиций как нового состояния
         *
         * Одновременно формируется индекс состояний по позициям.
         *
         * \param state     Список позиций
         * \param state_no  Номер состояния
         */
        void addState(parser::FsmState_t state, size_t state_no);
    };

}

#endif // simodo_interpret_host_fuze_ParsingTableBuilder_LR1
